import sys
reload(sys)
sys.setdefaultencoding( "utf-8" ) # since there can easily be UTF8 characters in the file

from statbook import *
import xml.dom.minidom as dom
import os

class SimpleDXML:
    def __init__(self):
        self.dxmlDoc = dom.Document()
        self.dxml = self.dxmlDoc.appendChild(self.dxmlDoc.createElement('derbyxml'))
    def createElement(self, elementName, parent, attrs = None):
        retval = parent.appendChild(self.dxmlDoc.createElement(elementName))
        if attrs:
            for key in attrs:
                retval.attributes[key] = attrs[key]
        return retval
    def newBout(self):
        self.boutXML = self.createElement('bout',self.dxml)
        self.homeTeam = self.createElement('team',self.boutXML)
        self.awayTeam = self.createElement('team',self.boutXML)
        self.firstPeriod = self.createElement('period',self.boutXML, {'number':'1'})
        self.secondPeriod = self.createElement('period',self.boutXML, {'number':'2'})

    def saveToFile(self,f):
        f.write(self.dxmlDoc.toprettyxml())
    def toprettyxml(self):
        return self.dxmlDoc.toprettyxml()

    def importTeam(self, teamXML, teamSB):
        teamXML.attributes['name'] = teamSB.team
        teamXML.attributes['league'] = teamSB.league
        for skater in teamSB.skaters:
            skaterXML = self.createElement('person',teamXML)
            skaterXML.attributes['name'] = skater.name
            if skater.number[-1] == "*": # use * suffix to denote a non-skating alt in the IGRF
                # NB that this skater should not appear anywhere else in the bout info, since
                # she is a non-skating alt
                skaterXML.attributes['number'] = skater.number[:-1]
                skater.number = skater.number[:-1]
                skaterXML.attributes['role'] = 'alt'
            else:
                skaterXML.attributes['number'] = skater.number
                skaterXML.attributes['role'] = 'skater'
    
    def importLineup(self, jamXML, LU, jamNumber, teamXML):
        # LU is "P,B,B,B,J"
        teamName = teamXML.attributes['name'].value
        pbbj = LU.LineupForJam(jamNumber)
        if pbbj:
            isPivot = True
            for skater in pbbj:
                if skater == None:
                    continue # missing a skater
                lineupXML = self.createElement('lineup',jamXML,{'team':teamName,'skater':skater})
                if isPivot and LU.JamHasPivot(jamNumber):
                    lineupXML.attributes['position'] = 'pivot'
                elif skater == pbbj[-1]:
                    lineupXML.attributes['position'] = 'jammer'
                else:
                    lineupXML.attributes['position'] = 'blocker'
                isPivot = False
                lineupXML.attributes['team'] = teamName
                lineupXML.attributes['skater'] = skater
    
    def importPasses(self, jamXML, SK, jamNumber, teamXML):
        teamName = teamXML.attributes['name'].value
        hasStarPass = SK.HasStarPass(jamNumber)
        for starPass in (False, True):
            if starPass and not hasStarPass:
                break
            jammer = SK.Jammer(jamNumber, starPass)
            if not SK.JamNP(jamNumber, starPass):
                # create the initial pass element (we have no good way to extract any initial pass points)
                self.createElement('pass', jamXML, {'team':teamName,'number':'1','points':'0'})
            for ps in range(2,self.statbook.version.maxNumPasses):
                pts = SK.JamPassPoints(jamNumber, ps, starPass)
                if pts == None:
                    continue
                if pts == '-': # ignore the '-' for NP
                    continue
                self.createElement('pass', jamXML, {'team':teamName,'number':str(int(ps)),'points':str(int(pts))})
            if hasStarPass and not starPass: # add the star pass here
                self.createElement('star-pass', jamXML, {'team':teamName})
            if SK.JamLead(jamNumber, starPass):
                self.createElement('lead', jamXML, {'team':teamName,'skater':jammer})
            if SK.JamLost(jamNumber, starPass):
                self.createElement('lost', jamXML, {'team':teamName,'skater':jammer})
            if SK.JamCall(jamNumber, starPass):
                self.createElement('call', jamXML, {'team':teamName,'skater':jammer})
            if SK.JamInj(jamNumber, starPass):
                self.createElement('inj', jamXML) # injury is not team SK specific
                
    def importPenalty(self, jamXML, PT, jamNumber, teamXML):
        teamName = teamXML.attributes['name'].value
        for skaterIndex in range(0,20):
            skater = PT.Skater(skaterIndex)
            if not skater:
                continue
            # we should probably drop support for minor penalties
            for pi in range(0,28):
                penalty = PT.MinorPenalty(skaterIndex, pi)
                if not penalty:
                    continue
                penaltyJamNumber = penalty[1]
                if penaltyJamNumber != jamNumber:
                    continue
                self.createElement('penalty',jamXML,{'skater':skater,'team':teamName,'penalty':penalty[0],'severity':'minor'})
            # need to support more penalties
            for pi in range(0,7):
                penalty = PT.MajorPenalty(skaterIndex, pi)
                if not penalty:
                    continue
                penaltyJamNumber = penalty[1]
                if jamNumber != penaltyJamNumber:
                    continue
                self.createElement('penalty',jamXML,{'skater':skater,'team':teamName,'penalty':penalty[0],'severity':'major'})
            penalty = PT.Expulsion(skaterIndex)
            if penalty and penalty[1] == jamNumber:
                self.createElement('penalty',jamXML,{'skater':skater,'team':teamName,'penalty':penalty[0],'severity':'expulsion'})

    def importJam(self, periodXML, periodIndex, jamNumber, statbook):
        self.statbook = statbook
        homeSK = statbook.home.scorekeeper[periodIndex]
        awaySK = statbook.away.scorekeeper[periodIndex]
        if jamNumber > homeSK.NumberOfJams():
            return
        homeLU = statbook.home.lineupTracker[periodIndex]
        awayLU = statbook.away.lineupTracker[periodIndex]
        homePT = statbook.home.penaltyTracker[periodIndex]
        awayPT = statbook.away.penaltyTracker[periodIndex]
        jamXML = self.createElement('jam', periodXML)
        jamXML.attributes['number'] = str(jamNumber)
        self.importLineup(jamXML, homeLU, jamNumber, self.homeTeam)
        self.importLineup(jamXML, awayLU, jamNumber, self.awayTeam)
        self.importPasses(jamXML, homeSK, jamNumber, self.homeTeam)
        self.importPasses(jamXML, awaySK, jamNumber, self.awayTeam)
        self.importPenalty(jamXML, homePT, jamNumber, self.homeTeam)
        self.importPenalty(jamXML, awayPT, jamNumber, self.awayTeam)
    def importActionError(self, periodXML, kind, teamSB, fn, labels):
        si = 0
        teamName = teamSB.team
        for skater in teamSB.skaters:
            results = fn(si)
            si += 1
            if not results:
                continue
            for label,count in zip(labels, results):
                if count:
                    attrs = {
                        'count': str(count),
                        'team': teamName,
                        'skater' : skater.number
                    };
                    xml = self.createElement(kind, periodXML, attrs)
                    xml.appendChild(self.dxmlDoc.createTextNode(label))
                
    def importPeriod(self, periodXML, periodIndex, statbook):
        for jn in range(1,statbook.version.maxNumJams):
            self.importJam(periodXML, periodIndex, jn, statbook)
        # since action/errors are a per-period thing...
        if statbook.version.hasActionsErrors:
            for team in (statbook.home, statbook.away):
                self.importActionError(periodXML, 'action', team, team.actions[periodIndex].AssistsForSkater, ["1/4 Track Jammer Block", "Jammer Force Out","Hit On Jammer","Jammer Knockdown","Block Assist"]);
                self.importActionError(periodXML, 'action', team, team.actions[periodIndex].AttacksForSkater, ["Offensive Block","Offensive Knockdown","Whip","Push","Bulldozer"]);
                self.importActionError(periodXML, 'error', team, team.errors[periodIndex].ErrorsForSkater, ["Juked","Missed Hit","Ineffective Hit","Hit And Fall","Knocked Down"]);
                self.importActionError(periodXML, 'error', team, team.errors[periodIndex].JammerActionsForSkater, ["Offensive Block Assist","Juke","Jump","Rolloff","Hip Whip"]);

    def importStatBook(self,statbook):
        self.newBout()
        def TimeToStr(x):
            if type(x) == type("") or type(x) == type(u""):
                return x # we assume time format is correct
            x = x * 24 * 60
            return "%.2d:%.2d" % (int(x / 60), int(round(x)) % 60)
        boutinfo = book.BoutInfo()
        self.boutXML.setAttribute("location", str(boutinfo['location']))
        self.boutXML.setAttribute("date", str(boutinfo['date']))
        self.boutXML.setAttribute("startTime", TimeToStr(boutinfo['start']))
        if boutinfo.has_key('end'):
            self.boutXML.setAttribute("endTime", TimeToStr(boutinfo['end']))
        self.boutXML.setAttribute("city", str(boutinfo['city']))
        self.boutXML.setAttribute("state", str(boutinfo['state']))

        self.importTeam(self.homeTeam, statbook.home)
        self.importTeam(self.awayTeam, statbook.away)
        self.importPeriod(self.firstPeriod, 0, statbook)
        self.importPeriod(self.secondPeriod, 1, statbook)

    
if __name__ == '__main__':
    import cgitb
    cgitb.enable(format='text')
    
    from optparse import OptionParser
    parser = OptionParser("usage: %prog [options] arg")
    parser.add_option("-f", "--file", dest="outname",
                      help="write report to FILE (--file - to print to stdout)", metavar="FILE")
    parser.add_option("-v", "--verbose",
                      action="store_true", dest="verbose", default=False,
                      help="print detailed progress")
    parser.add_option("-p", "--period",
                      dest="period", default=30,
                      help="period duration (20 or 30)")
    parser.add_option("-x", "--index",
                        dest="index", default=None,
                        help="Generate all files from index file", metavar="INDEXFILE")
    outname = None
    (options, args) = parser.parse_args()
    if len(args):
        filelist = args
    else:
        if not options.index:
            parser.error("Missing source file(s)")
    outname = '-'
    dxmlDoc = None
    dxml = None
    if options.index:
        from xml.dom.minidom import parse
        import uuid as UUID
        indexXML = parse(options.index)
        indexDXML = indexXML.getElementsByTagName('derbyxml')[0]
#        league = indexXML.getElementsByTagName('league')[0]
#        print league
        rootDirectory = os.path.dirname(options.index)
        print rootDirectory
        # find out what we've already generated
        bouts = {};
        for bout in indexDXML.getElementsByTagName('bout'):
            bouts[bout.attributes['href'].value] = bout
        for statbook in indexDXML.getElementsByTagName('statbook'):
            # use the uuid as the href
            if statbook.hasAttribute('uuid'):
                uuid = statbook.attributes['uuid'].value
            else:
                uuid = str(UUID.uuid1())
                statbook.setAttribute('uuid',uuid)
            if bouts.has_key(uuid):
                continue # we will assume it is correct already
            else:
                book = StatBook(statbook.attributes['src'].value)
                dxmlDoc = SimpleDXML()
                dxmlDoc.importStatBook(book)
                outfileName = os.path.join(rootDirectory,uuid+os.path.extsep+"derbyxml")
                outfile = file(outfileName,"w")
                dxmlDoc.saveToFile(outfile)
                # update the index
                boutIndex = indexXML.createElement('bout')
                indexDXML.appendChild(boutIndex)
                boutIndex.attributes['href'] = uuid
                boutIndex.attributes['home-name'] = book.home.teamName
                boutIndex.attributes['home-score'] = str(int(book.home.TotalScore()))
                boutIndex.attributes['away-name'] = book.away.teamName
                boutIndex.attributes['away-score'] = str(int(book.away.TotalScore()))
                boutIndex.attributes['date'] = str(book.BoutInfo()['date'])
                for key in statbook.attributes.keys():
                    if key[:5] == "bout-":
                        boutIndex.attributes[key[5:]] = statbook.attributes[key].value
                if 'name' in statbook.attributes.keys():
                    boutIndex.attributes['name'] = statbook.attributes['name']
                print "Generated bout data", boutIndex.toprettyxml()
        indexFile = file(options.index,"w")
        print "New index\n",indexXML.toprettyxml()
        indexFile.write(indexXML.toxml())
        
    else:
        for fname in filelist:
    #        print fname
            book = StatBook(fname)
            if not dxmlDoc:
                dxmlDoc = SimpleDXML()
            dxmlDoc.importStatBook(book)
            
            outfile = None
    #        print "Saving file to ",outname
            if outname == '-':
                pass # going to std out when we are done
            else:
                if outname == None:
                    outfile = file(os.path.splitext(fname)[0]+os.path.extsep+"derbyxml","w")
                else:
                    outfile = file(outname,"w")
                dxmlDoc.saveToFile(outfile)
                dxmlDoc = None
        if dxmlDoc:
            print dxmlDoc.toprettyxml()
            
        

